﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using Telerik.Web.Mvc;

namespace Sausage.Web.Domain
{
    public class ProjectHelper
    {
        public static Project GetProjectByName(string projectName)
        {
            using (var context = new SausageEntities())
            {
                return context.Project.Include("ProjectCategory").Include("Organization").Include("ProjectAttachment").FirstOrDefault(project => project.ProjectName == projectName);
            }
        }

        public static Project GetProjectByCode(string projectCode)
        {
            using (var context = new SausageEntities())
            {
                return context.Project.Include("ProjectCategory").Include("Organization").Include("ProjectAttachment").FirstOrDefault(project => project.ProjectCode == projectCode);
            }
        }

        public static Project GetProjectByID(Guid projectID)
        {
            using (var context = new SausageEntities())
            {
                return context.Project.Include("ProjectCategory").Include("Organization").Include("ProjectAttachment").FirstOrDefault(item => item.ProjectID == projectID);
            }
        }

        public static void DeleteProject(Guid projectID)
        {
            using (var context = new SausageEntities())
            {
                //Delete the Project attachment.
                var attachments = context.ProjectAttachment.Where(attachment => attachment.ProjectID == projectID).ToList();
                var sourceFolder = HttpContext.Current.Server.MapPath(Utility.ProjectFolder);
                foreach (var attachment in attachments)
                {
                    context.CreateObjectSet<ProjectAttachment>().Attach(attachment);
                    try
                    {
                        string sourcePath = string.Concat(sourceFolder,
                                                          Path.DirectorySeparatorChar, attachment.AttachmentID,
                                                          attachment.FileExtension);
                        if (File.Exists(sourcePath))
                            File.Delete(sourcePath);
                    }
                    catch {/*do nothing*/}
                    context.ObjectStateManager.ChangeObjectState(attachment, EntityState.Deleted);
                }

                //Delete the Project machine
                var machines = context.ProjectMachine.Where(machine => machine.ProjectID == projectID).ToList();
                foreach (var machine in machines)
                {
                    context.CreateObjectSet<ProjectMachine>().Attach(machine);
                    context.ObjectStateManager.ChangeObjectState(machine, EntityState.Deleted);
                }

                //Delete the Project material
                var materials = context.ProjectMaterial.Where(material => material.ProjectID == projectID).ToList();
                foreach (var material in materials)
                {
                    context.CreateObjectSet<ProjectMaterial>().Attach(material);
                    context.ObjectStateManager.ChangeObjectState(material, EntityState.Deleted);
                }

                //Delete the Project journal
                var journals = context.ProjectJournal.Where(journal => journal.ProjectID == projectID).ToList();
                foreach (var journal in journals)
                {
                    //Delete the Project photo
                    var photos = context.ProjectPhoto.Where(photo => photo.JournalID == journal.JournalID).ToList();
                    foreach (var photo in photos)
                    {
                        context.CreateObjectSet<ProjectPhoto>().Attach(photo);
                        context.ObjectStateManager.ChangeObjectState(photo, EntityState.Deleted);
                    }
                    context.CreateObjectSet<ProjectJournal>().Attach(journal);
                    context.ObjectStateManager.ChangeObjectState(journal, EntityState.Deleted);
                }

                //Delete the Project quantities.
                var quantities = context.ProjectQuantity.Where(quantity => quantity.ProjectID == projectID).ToList();
                foreach (var quantity in quantities)
                {
                    context.CreateObjectSet<ProjectQuantity>().Attach(quantity);
                    context.ObjectStateManager.ChangeObjectState(quantity, EntityState.Deleted);
                }

                //Delete the Project
                var project = new Project { ProjectID = projectID };
                context.CreateObjectSet<Project>().Attach(project);
                context.ObjectStateManager.ChangeObjectState(project, EntityState.Deleted);

                context.SaveChanges();
            }
        }

        public static void UpdateProject(ProjectListRow data)
        {
            using (var context = new SausageEntities())
            {
                var project = context.Project.FirstOrDefault(item => item.ProjectID == data.ProjectID);
                if (project == null)
                    return;

                project.ProjectCode = string.Format("{0:yyyy}-{1}-{2}", project.CreateDate, Helper.CurrentPrincipal.Organization.OrganizationCode, data.ProjectName); ;
                project.ProjectName = data.ProjectName;
                project.CategoryID = data.CategoryID;
                project.Roadway = data.Roadway;
                project.BeginStake = data.BeginStake;
                project.EndStake = data.EndStake;
                project.GrantNumber = data.GrantNumber;
                project.StartDate = data.StartDate;
                project.CompletionDate = data.CompletionDate;
                project.ProjectLeader = data.ProjectLeader;
                project.TechnicalChief = data.TechnicalChief;
                project.QualityChief = data.QualityChief;
                project.Budget = data.Budget;
                project.ApprovedBudget = data.ApprovedBudget;
                context.SaveChanges();
            }
        }

        public static Guid CreateProject(ProjectListRow data)
        {
            //创建工程编号
            Guid projectID = Guid.NewGuid();

            using (var context = new SausageEntities())
            {
                var project = new Project();
                project.ProjectID = projectID;
                project.ProjectCode = string.Format("{0:yyyy}-{1}-{2}", DateTime.Now, Helper.CurrentPrincipal.Organization.OrganizationCode, data.ProjectName);
                project.ProjectName = data.ProjectName;
                project.OrganizationID = Helper.CurrentPrincipal.User.OrganizationID;
                project.CategoryID = data.CategoryID;
                project.Roadway = data.Roadway;
                project.BeginStake = data.BeginStake;
                project.EndStake = data.EndStake;
                project.GrantNumber = data.GrantNumber;
                project.StartDate = data.StartDate;
                project.CompletionDate = data.CompletionDate;
                project.ProjectLeader = data.ProjectLeader;
                project.TechnicalChief = data.TechnicalChief;
                project.QualityChief = data.QualityChief;
                project.Budget = data.Budget;
                project.ApprovedBudget = data.ApprovedBudget;
                project.CreateDate = DateTime.Now;
                project.State = (int)ProjectStateEnum.Unsubmit;
                context.AddToProject(project);
                context.SaveChanges();
            }

            if (data.Attachments != null && data.Attachments.Length > 0)
                FileUploadHelper.MoveFileFromTempToProjectAttachment(projectID, data.Attachments);

            //返回工程编号
            return projectID;
        }

        public static bool DeleteAttachment(ProjectAttachmentModel attachment)
        {
            using (var context = new SausageEntities())
            {
                var target =
                    context.ProjectAttachment.FirstOrDefault(item => item.AttachmentID == attachment.AttachmentID);
                if (target == null)
                    return true;

                string filePath = string.Concat(HttpContext.Current.Server.MapPath(Utility.ProjectFolder),
                                                Path.DirectorySeparatorChar, target.AttachmentID, target.FileExtension);

                try
                {
                    if (File.Exists(filePath))
                        File.Delete(filePath);

                    context.DeleteObject(target);
                    context.SaveChanges();
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }

        public static List<ProjectAttachment> GetProjectAttachment(Guid projectID)
        {
            var organization = OrganizationHelper.GetAllowedOrganizationList();
            using (var context = new SausageEntities())
            {
                return context.ProjectAttachment.Where(item => item.ProjectID == projectID && (item.IsOpen || organization.Contains(item.OrganizationID))).ToList();
            }
        }

        public static ProjectAttachment GetAttachment(Guid attachmentID)
        {
            var organization = OrganizationHelper.GetAllowedOrganizationList();
            using (var context = new SausageEntities())
            {
                return context.ProjectAttachment.FirstOrDefault(item => item.AttachmentID == attachmentID && (item.IsOpen || organization.Contains(item.OrganizationID)));
            }
        }

        public static GridModel<object> Select(JosnPagingQueryModel query)
        {
            using (var context = new SausageEntities())
            {
                return
                    QueryProject(context.Project, query);
            }
        }

        public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
        {
            var organization = OrganizationHelper.GetAllowedOrganizationList();
            using (var context = new SausageEntities())
            {
                return
                    QueryProject(
                        context.Project.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)ProjectStateEnum.Unsubmit ||
                             item.State == (int)ProjectStateEnum.AuditRejected)),
                        query);
            }
        }

        public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
        {
            var organization = OrganizationHelper.GetAllowedOrganizationList();
            using (var context = new SausageEntities())
            {
                return
                    QueryProject(context.Project.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)ProjectStateEnum.Submitted)
                    , query);
            }
        }

        public static GridModel<object> ClosedSelect(JosnPagingQueryModel query)
        {
            var organization = OrganizationHelper.GetAllowedOrganizationList();
            using (var context = new SausageEntities())
            {
                return
                    QueryProject(context.Project.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)ProjectStateEnum.Closed)
                    , query);
            }
        }

        public static GridModel<object> ActiveSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryProject(context.Project.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)ProjectStateEnum.Audited)
                    , query);
            }
        }

        public static List<object> GetProjectReference()
        {
            var organizations = OrganizationHelper.GetAllowedOrganizationList();
            using (SausageEntities context = new SausageEntities())
            {
                return (from item in context.Project
                        where
                            item.State == (int)ProjectStateEnum.Audited && organizations.Contains(item.OrganizationID)
                        select new
                                   {
                                       ID = item.ProjectID,
                                       Code = item.ProjectCode,
                                       Name = item.ProjectName
                                   }).ToList<object>();
            }
        }

        public static void ExecuteSubmit(Guid projectID)
        {
            using (SausageEntities context = new SausageEntities())
            {
                Project project = context.Project.FirstOrDefault(item => item.ProjectID == projectID);
                if (null != project)
                {
                    project.State = (int)ProjectStateEnum.Submitted;
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteClose(Guid projectID)
        {
            using (SausageEntities context = new SausageEntities())
            {
                Project project = context.Project.FirstOrDefault(item => item.ProjectID == projectID);
                if (null != project)
                {
                    project.State = (int)ProjectStateEnum.Closed;
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteConfirm(Guid[] projects, bool passed)
        {
            //判定是否有编号
            if (null != projects && projects.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.Project.Where(item => projects.Contains(item.ProjectID)).ToList();

                    foreach (var project in list)
                    {
                        project.Approver = Helper.CurrentPrincipal.User.UserName;
                        project.ApprovedDate = DateTime.Now;
                        project.State = passed
                                            ? (int)ProjectStateEnum.Audited
                                            : (int)ProjectStateEnum.AuditRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        private static GridModel<object> QueryProject(IQueryable<Project> source, JosnPagingQueryModel query)
        {
            var result = UIHelper.GetGridModelFromQueryModel<Project>(
                source,
                query.page,
                query.limit,
                GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel));

            var list = result.Data.Select(project => new
            {
                ProjectID = project.ProjectID,
                ProjectCode = project.ProjectCode,
                ProjectName = project.ProjectName,
                Organization = project.Organization.OrganizationName,
                Category = project.ProjectCategory.ItemName,
                CategoryID = project.CategoryID,
                Roadway = project.Roadway,
                BeginStake = project.BeginStake,
                EndStake = project.EndStake,
                GrantNumber = project.GrantNumber,
                StartDate = project.StartDate,
                CompletionDate = project.CompletionDate,
                ProjectLeader = project.ProjectLeader,
                TechnicalChief = project.TechnicalChief,
                QualityChief = project.QualityChief,
                Budget = project.Budget,
                ApprovedBudget = project.ApprovedBudget,
                CreateDate = project.CreateDate,
                ApprovedDate = project.ApprovedDate,
                CloseDate = project.CloseDate,
                State = project.State
            }).ToList();

            return new GridModel<object>()
            {
                Aggregates = result.Aggregates,
                Data = list,
                Total = result.Total
            };
        }

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels)
        {
            var filterList = new List<IFilterDescriptor>();
            foreach (var item in filterModels)
            {
                if (string.IsNullOrEmpty(item.value))
                    continue;

                if (item.property == "OrganizationID" || item.property == "CategoryID")
                {
                    var targetID = Guid.Parse(item.value);
                    if (targetID != Guid.Empty)
                        filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
                }
                else if (item.property == "StartDate_L") //startData - begin
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("StartDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "StartDate_H") // startDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("StartDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else //other filter.
                    filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
            }
            return filterList;
        }

        private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
        {
            //convert the sort description.
            var sortList = new List<SortDescriptor>();
            foreach (var item in sortModels)
            {
                var descriptor = new SortDescriptor()
                                     {
                                         Member = item.property,
                                         SortDirection =
                                             item.direction.ToLower() == "desc"
                                                 ? ListSortDirection.Descending
                                                 : ListSortDirection.Ascending
                                     };

                if (descriptor.Member == "Organization")
                    descriptor.Member = "Organization.OrganizationName";
                else if (descriptor.Member == "Category")
                    descriptor.Member = "ProjectCategory.ItemName";

                sortList.Add(descriptor);
            }
            return sortList;
        }
    }
}
